// nodeModel.go
package models

import (
	"context"
	"fmt"
	"log"
	"myk8s/common"

	policyv1 "k8s.io/api/policy/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	//"k8s.io/apimachinery/pkg/runtime"
	//"sigs.k8s.io/yaml"
)

type Kubenode struct {
	NodeName    string `json:"nodeName"`    //节点名称
	NodeIp      string `json:"nodeIp"`      //节点IP
	NodeRole    string `json:"nodeRole"`    //读取标签中的角色
	NodeState   string `json:"nodeState"`   //读取conditions中为true的状态
	NodeInfo    string `json:"nodeInfo"`    //系统/kubelet/containerd/内核版本
	PodCIDR     string `json:"podCIDR"`     //Endpoint/PodCIDR
	Capacity    string `json:"capacity"`    //容量/可分配
	Allocatable string `json:"allocatable"` //资源利用率、磁盘、内存、负载、CPU
	CreateTime  string `json:"createTime"`  //创建时间
}

type NodeConditions struct {
	Ctype              string `json:"ctype"`
	Status             string `json:"status"`
	LastHertbeatTime   string `json:"lastHertbeatTime"`
	LastTransitionTime string `json:"lastTransitionTime"`
	Reason             string `json:"reason"`
	Message            string `json:"message"`
}

func NodeList(kubeconfig string) ([]Kubenode, error) {
	//通过kubeconfig集群认证文件生成一个客户端操作对象clientset
	clientset := common.ClientSet(kubeconfig)
	nodeList, err := clientset.CoreV1().Nodes().List(context.TODO(), metav1.ListOptions{})
	if err != nil {
		log.Printf("list nodes error:%v\n", err)
	}
	var NodeArry = make([]Kubenode, 0)
	for _, node := range nodeList.Items {
		var nodeStatus = "Ready:True"
		for _, vv := range node.Status.Conditions {
			if vv.Status == "True" || vv.Status == "Unknown" {
				nodeStatus = fmt.Sprintf("%s:%s", vv.Type, vv.Status)
				break
			} else {
				nodeStatus = fmt.Sprintf("%s:%s", vv.Type, vv.Status)
			}
		}
		var nodeRole = node.Labels["node-role.kubernetes.io/work"]
		if nodeRole == "" {
			nodeRole = "Worker"
		}
		var bbb = make([]NodeConditions, 0)
		for _, v1 := range node.Status.Conditions {
			xItems := &NodeConditions{
				LastTransitionTime: v1.LastTransitionTime.Format("2006-01-02 15:04:05"),
				LastHertbeatTime:   v1.LastHeartbeatTime.Format("2006-01-02 15:04:05"),
				Message:            v1.Message,
				Reason:             v1.Reason,
				Status:             fmt.Sprintf("%v", v1.Status),
				Ctype:              fmt.Sprintf("%v", v1.Type),
			}
			bbb = append(bbb, *xItems)
		}
		NodeArry = append(NodeArry, *&Kubenode{
			NodeName:    node.Name,
			NodeIp:      node.Status.Addresses[0].Address,
			NodeRole:    nodeRole,
			NodeState:   nodeStatus,
			NodeInfo:    fmt.Sprintf("KernelVersion:%s,OS:%s,KubeletVersion:%s,Container:%s", node.Status.NodeInfo.KernelVersion, node.Status.NodeInfo.OSImage, node.Status.NodeInfo.KubeletVersion, node.Status.NodeInfo.ContainerRuntimeVersion),
			PodCIDR:     fmt.Sprintf("PodCIDR:%s", node.Spec.PodCIDR),
			Capacity:    fmt.Sprintf("CPU:%d,Mem:%dMi,Disk:%dGi,Pods:%d", node.Status.Capacity.Cpu().Value(), node.Status.Capacity.Memory().Value()/1024/1024, node.Status.Capacity.StorageEphemeral().Value()/1024/1024/1024, node.Status.Capacity.Pods().Value()),
			Allocatable: fmt.Sprintf("CPU:%d,Mem:%dMi,Disk:%dGi,Pods:%d", node.Status.Allocatable.Cpu().Value(), node.Status.Allocatable.Memory().Value()/1024/1024, node.Status.Allocatable.StorageEphemeral().Value()/1024/1024/1024, node.Status.Allocatable.Pods().Value()),
			CreateTime:  fmt.Sprintf("%s", node.ObjectMeta.CreationTimestamp.Time.Format("2006-01-02 15:04:05")),
		})
	}
	return NodeArry, err
}

//节点排水
func NodeDrain(kubeconfig, nodeName string) error {
	clientset := common.ClientSet(kubeconfig)
	podlist, err := PodList(kubeconfig, "", "", "", "", "", nodeName)
	if err != nil {
		log.Printf("[ERROR] NodeDrain GetPodList Fail:%s\n", err)
		return err
	}
	for _, pod := range podlist {
		if pod.PodPhase == "Running" {
			var periodSeconds int64
			eviction := &policyv1.Eviction{
				ObjectMeta: metav1.ObjectMeta{
					Name:      pod.PodName,
					Namespace: pod.NameSpace,
				},
				DeleteOptions: &metav1.DeleteOptions{
					GracePeriodSeconds: &periodSeconds,
				},
			}
			err = clientset.PolicyV1().Evictions(pod.NameSpace).Evict(context.Background(), eviction)
			if err != nil {
				log.Printf("[ERROR] NodeDrain pod Evict Fail:%s\n", err)
				return err
			}
		}
	}
	return nil
}

//节点调度设置
func NodeUnschedulable(kubeconfig, nodeName string, value bool) error {
	clientset := common.ClientSet(kubeconfig)
	node, err := clientset.CoreV1().Nodes().Get(context.TODO(), nodeName, metav1.GetOptions{})
	if err != nil {
		return err
	}
	node.Spec.Unschedulable = value
	_, err = clientset.CoreV1().Nodes().Update(context.Background(), node, metav1.UpdateOptions{})
	return err
}
